﻿using System;
using System.Collections.Generic;
using System.Linq;
using DLM.Services.Interfaces;
using DLM.Domain.Model;
using DLM.Domain.Repositories;
using DLM.Web.ViewModel;
using DLM.Infrastructure.Exception;
using DLM.Services.BonusRule;
using DLM.Domain.DTO;
using System.Web.Mvc;
using DLM.Infrastructure.Email;

namespace DLM.Services.Implementations
{
    public class PartyService : IPartyService
    {

        private IPartyRepository partyRepository;
        private IUserRepository userRepository;
        private IUserPartyAssociationRepository userPartyAssRepository;
        private IRemarkRepository remarkRepository;
        private IInvitationRepository invitationRepository;
        private IBonusLogRepository bonusLogRepository;
        private IBonusRepository bonusRepository;
        private ITypeRepository partyTypeRepository;
        private IModalityRepository modalityRepository;
        private ISupplierRepository supplierRepository;
        private IEmailService emailService;
        private IEmailInvitationRepository emailInvitationRepository;
        private IBonusCalculateStepRepository bonusCalculateRepository;
        private IPartyAlbumRepository partyAlbumRepository;

        public PartyService(IPartyRepository partyRepository,
            IUserRepository userRepository,
            IUserPartyAssociationRepository userPartyAssRepository,
            IRemarkRepository remarkRepository,
            IInvitationRepository invitationRepository,
            IBonusLogRepository bonusLogRepository,
            IBonusRepository bonusRepository,
            ITypeRepository partyTypeRepository,
            IModalityRepository modalityRepository,
            ISupplierRepository supplierRepository,
            IEmailService emailService,
            IEmailInvitationRepository emailInvitationRepository,
            IBonusCalculateStepRepository bonusCalculateRepository,
            IPartyAlbumRepository partyAlbumRepository)
        {
            this.partyRepository = partyRepository;
            this.userRepository = userRepository;
            this.userPartyAssRepository = userPartyAssRepository;
            this.remarkRepository = remarkRepository;
            this.invitationRepository = invitationRepository;
            this.bonusLogRepository = bonusLogRepository;
            this.bonusRepository = bonusRepository;
            this.partyTypeRepository = partyTypeRepository;
            this.modalityRepository = modalityRepository;
            this.supplierRepository = supplierRepository;
            this.emailService = emailService;
            this.emailInvitationRepository = emailInvitationRepository;
            this.bonusCalculateRepository = bonusCalculateRepository;
            this.partyAlbumRepository = partyAlbumRepository;
        }


        #region Party

        public void AddParty(PartyPageView view)
        {
            if (view == null)
            {
                throw new ArgumentNullException("View cannot be null!");
            }
            Party party = view.Party;
            party.CreateDate = DateTime.Now;
            party.Status = (int)PartyStatus.PendingForApproval;
            User user = this.userRepository.FindByName(view.UserName);
            UserPartyAssociation upAssociation = new UserPartyAssociation();
            upAssociation.UserID = user.UserID;
            upAssociation.AssociationDate = DateTime.Now;
            party.UserPartyAssociation = new List<UserPartyAssociation> 
            {
                upAssociation
            };
            upAssociation.IsLead = 1;

            if (!CanPublish(upAssociation,party.PartyDate.Value,party.EndDate))
            {
                throw new PublishFailedException("您已经在一个小时内发布或者参加了活动，不允许继续发布！");
            }
  

            var bonus = this.bonusRepository.FindByUser(upAssociation.UserID);
            if (bonus.Bonuses.HasValue)
            {
                if (bonus.Bonuses.Value < 15)
                {
                    throw new BounsNotEnoughException("您的积分目前不够，请充值!");
                }
            }

            this.partyRepository.Add(party);

            if (upAssociation != null)
            {
                BonusCalculateStep tmpStep = new BonusCalculateStep();
                tmpStep.OriginalBonus = bonus.Bonuses.Value;
                tmpStep.UserID = upAssociation.UserID;
                tmpStep.PartyID = upAssociation.PartyID;
                tmpStep.IsSuccess = false;
                tmpStep.PartyStatus = (int)PartyStatus.PendingForApproval;
                tmpStep.CreateDate = DateTime.Now;
                tmpStep.Step = "TemporaryDistrain";
                tmpStep.Deduct = BonusRuleFactory.GetBonusRuleService().TemporaryDistrain;
                this.bonusCalculateRepository.Add(tmpStep);

                bonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                bonus.UpdateDate = DateTime.Now;
                this.bonusRepository.Save(bonus);

                bonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                bonus.UpdateDate = DateTime.Now;
                this.bonusRepository.Save(bonus);


                // Add bonus log
                BonusLog log = new BonusLog
                {
                    Bonus = tmpStep.Deduct,
                    CreateDate = DateTime.Now,
                    PartyID = upAssociation.PartyID,
                    UserID = upAssociation.UserID,
                    Desc = "参加活动暂扣积分"
                };
                this.bonusLogRepository.Add(log);


            }
        }

        public void UpdateParty(Party party)
        {
            if (party == null)
            {
                throw new ArgumentNullException("Party cannot be null!");
            }
            this.partyRepository.Save(party);
        }

        public void RemoveParty(Party party)
        {
            if (party == null)
            {
                throw new ArgumentNullException("Party cannot be null!");
            }
            this.partyRepository.Remove(party);
        }

        public IEnumerable<Party> GetParty()
        {
            return this.partyRepository.FindAll();
        }

        public IEnumerable<Party> GetParty(int pageIndex, int pageSize)
        {
            if (pageIndex < 0 || pageSize < 0)
            {
                throw new ArgumentOutOfRangeException("Index cannot be negative!");
            }
            return this.partyRepository.FindAll(p => p.Subject != null, pageIndex, pageSize);
        }

        public IEnumerable<Party> GetLatestParty(PartyType type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("Type cannot be null!");
            }
            return this.partyRepository.FindByType(type, PartyStatus.Open, 0, 6);
        }

        public Party GetParty(int partyID)
        {
            if (partyID < 0)
            {
                throw new ArgumentException("Id null or negative!");
            }
            return this.partyRepository.FindBy(partyID);
        }

        public IEnumerable<Party> GetParty(PartyType type, int pageIndex, int pageSize)
        {
            if (type == null)
            {
                throw new ArgumentNullException("Type cannot be null!");
            }

            return this.partyRepository.FindAll(p => p.PartyType == (int)type, pageIndex, pageSize);
        }

        public IEnumerable<PartyDTO> ShowParty(PartyType type, int pageIndex, int pageSize)
        {
            if (type == null)
            {
                throw new ArgumentNullException("Type cannot be null!");
            }
            return this.partyRepository.FindDTOByType(type, PartyStatus.Open, pageIndex, pageSize);
        }

        public PartyPageView MyParty(PartyPageView view, int pageIndex, int pageSize)
        {
            if (view == null)
            {
                throw new ArgumentNullException("View cannot be null!");
            }

            view.MyPublish = this.partyRepository.FindMyPublished(view.UserName, pageIndex, pageSize);
            view.MyEngaged = this.partyRepository.FindMyEngaged(view.UserName, pageIndex, pageSize);


            return view;
        }


        public IEnumerable<Party> GetParty(PartyStatus staus, int pageIndex, int pageSize)
        {
            return this.partyRepository.FindAll(p => p.Status == (int)staus, pageIndex, pageSize);
        }


        public IEnumerable<Party> GetPartyByPblish(string publisher, int pageIndex, int pageSize)
        {
            if (string.IsNullOrEmpty(publisher))
            {
                throw new ArgumentNullException("Publisher");
            }
            return this.partyRepository.FindByPublisher(publisher, pageIndex, pageSize);
        }

        public void Attend(PartyPageView view)
        {
            if (view == null)
            {
                throw new ArgumentNullException("View cannot be null!");
            }
            UserPartyAssociation upAss = new UserPartyAssociation();
            upAss.IsLead = 0;
            upAss.PartyID = view.Party.PartyID;
            upAss.UserID = this.userRepository.FindByName(view.UserName).UserID;
            upAss.AssociationDate = DateTime.Now;

            if (!CanParticipateIn(upAss,view.Party.PartyDate.Value,view.Party.EndDate))
            {
                throw new PublishFailedException("您已经在一个小时内发布或者参加了活动，不允许继续参加活动！");
            }
            var bonus = this.bonusRepository.FindByUser(upAss.UserID);
            if (bonus.Bonuses.HasValue)
            {
                if (bonus.Bonuses.Value < 15)
                {
                    throw new BounsNotEnoughException("您的积分目前不够，请充值!");
                }
            }
            // Add attend
            this.userPartyAssRepository.Add(upAss);

            // Calculate bonus
            if (bonus != null)
            {
                BonusCalculateStep tmpStep = new BonusCalculateStep();
                tmpStep.OriginalBonus = bonus.Bonuses.Value;
                tmpStep.UserID = upAss.UserID;
                tmpStep.PartyID = upAss.PartyID;
                tmpStep.IsSuccess = false;
                tmpStep.PartyStatus = (int)PartyStatus.Open;
                tmpStep.CreateDate = DateTime.Now;
                tmpStep.Step = "TemporaryDistrain";
                tmpStep.Deduct = BonusRuleFactory.GetBonusRuleService().TemporaryDistrain;
                this.bonusCalculateRepository.Add(tmpStep);

                bonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                bonus.UpdateDate = DateTime.Now;
                this.bonusRepository.Save(bonus);


                // Add bonus log
                BonusLog log = new BonusLog
                {
                    Bonus = tmpStep.Deduct,
                    CreateDate = DateTime.Now,
                    PartyID = upAss.PartyID,
                    UserID = upAss.UserID,
                    Desc = "参加活动暂扣积分"
                };
                this.bonusLogRepository.Add(log);
            }
        }

        public void Quit(PartyPageView view)
        {
            if (view == null)
            {
                throw new ArgumentNullException("View cannot be null!");
            }
            int userID = this.userRepository.FindByName(view.UserName).UserID;
            var s = this.userPartyAssRepository.Where(p => p.PartyID == view.Party.PartyID && p.UserID == userID).FirstOrDefault();
            this.userPartyAssRepository.Remove(s);
            // Calculate bonus
            var bonus = this.bonusRepository.FindByUser(s.UserID);
            var party = this.partyRepository.FindBy(s.PartyID);

            if (bonus != null)
            {
                 BonusCalculateStep lastSteps = this.bonusCalculateRepository.FindByPartyAndUser(party.PartyID, userID)
                     .OrderByDescending(b=>b.CreateDate)
                    .FirstOrDefault(b => b.Step == "TemporaryDistrain");


                BonusCalculateStep tmpStep = new BonusCalculateStep();
                tmpStep.UserID = userID;
                tmpStep.PartyID = party.PartyID;
                tmpStep.PartyStatus = party.Status;
                tmpStep.IsSuccess = party.IsSuccess;
                tmpStep.CreateDate = DateTime.Now;
             

               

                if (party.Status == (int)PartyStatus.Freeze)
                {
                    tmpStep.Step = "Quit.Frozen";                
                    tmpStep.Deduct = BonusRuleFactory.GetBonusRuleService().Quit.Frozen;

                    if (bonus.Bonuses.Value != (lastSteps.OriginalBonus + lastSteps.Deduct))
                    {
                        tmpStep.OriginalBonus = bonus.Bonuses.Value + lastSteps.Deduct;
                        bonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                    }
                    else
                    {
                        tmpStep.OriginalBonus = lastSteps.OriginalBonus + lastSteps.Deduct;

                        bonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                    }

           
                }
                else
                {
                    tmpStep.Step = "Quit";
                    tmpStep.Deduct = -(BonusRuleFactory.GetBonusRuleService().TemporaryDistrain);

                    if (bonus.Bonuses.Value != (lastSteps.OriginalBonus+ lastSteps.Deduct))
                    {
                        tmpStep.OriginalBonus = bonus.Bonuses.Value + lastSteps.Deduct;
                        bonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                    }
                    else
                    {
                        tmpStep.OriginalBonus = lastSteps.OriginalBonus + lastSteps.Deduct;
                        bonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                    }
                }

                bonus.UpdateDate = DateTime.Now;
                this.bonusRepository.Save(bonus);

                bonusCalculateRepository.Add(tmpStep);

                    // Add bonus log
                 BonusLog log = new BonusLog
                 {
                        Bonus = tmpStep.Deduct,
                        CreateDate = DateTime.Now,
                        PartyID = s.PartyID,
                        UserID = s.UserID,
                        Desc = "退出活动退还积分"
                 };
                this.bonusLogRepository.Add(log);

            }
        }

        public IEnumerable<Party> SearchParty(string key, PartyType type)
        {
            IEnumerable<Party> list;
            if (!string.IsNullOrEmpty(key))
            {
                return list = this.partyRepository.FindAll(p => p.Location.Contains(key)
                    && p.PartyType == (int)type, 1, 6);
            }
            return null;

        }

        public bool IsAttended(string userName, int partyID)
        {
            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException("User name cannot be null!");
            }
            if (partyID < 0)
            {
                throw new ArgumentOutOfRangeException("Id cannot be negative!");
            }
            return this.partyRepository.IsExist(userName, partyID);
        }

        public bool IsLead(string userName, int partyID)
        {
            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException("User name cannot be null!");
            }
            if (partyID < 0)
            {
                throw new ArgumentOutOfRangeException("Id cannot be negative!");
            }
            return this.partyRepository.IsLead(userName, partyID);
        }


        public PartyDetailPageView ViewParty(int partyID, string userName)
        {
            if (partyID < 0)
            {
                throw new ArgumentNullException("Id cannot be negative!");
            }
            PartyDetailPageView view = new PartyDetailPageView();

            if (!string.IsNullOrEmpty(userName))
            {
                view.IsAttend = this.partyRepository.IsExist(userName, partyID);
                view.IsLead = this.partyRepository.IsLead(userName, partyID);

            }
            // view.party = this.partyRepository.FindBy(partyID);
            view.PartyDTO = this.partyRepository.FindViewDTO(partyID);
            
            //this.partyRepository.SuccessRate(view.PartyDTO.PublishAccount);
            view.Statistics = this.partyRepository.LeadStatistics(view.PartyDTO.PublishAccount);
            if (view.Statistics[0] == 0)
            {
                view.SuccessRate = 0;
            }
            else
            {
                view.SuccessRate = Math.Round( ((decimal)view.Statistics[1] / (decimal)view.Statistics[0]),2);
            }
          
            var list = this.partyRepository.FindParticipantProportion(partyID);
            view.Male = list.Where(p => p.Gender == false).Select(p => p.Count).FirstOrDefault();
            view.Female = list.Where(p => p.Gender == true).Select(p => p.Count).FirstOrDefault();
            if (view.PartyDTO.Status == (int)PartyStatus.Closed && !string.IsNullOrEmpty(userName))
            {
                view.CanLeaveMessage = this.remarkRepository.IsLeaveMessage(userName, partyID);
            }
            else
            {
                view.CanLeaveMessage = false;
            }


            return view;
        }
        #endregion


        public IEnumerable<PartyDTO> MyPublish(string userName, int pageIndex, int pageSize)
        {
            return this.partyRepository.FindMyPublished(userName, pageIndex, pageSize);
        }

        public IEnumerable<PartyDTO> MyEngaged(string userName, int pageIndex, int pageSize)
        {
            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException(userName);
            }
            return this.partyRepository.FindMyEngaged(userName, pageIndex, pageSize);
        }

        public IEnumerable<PartyDTO> MyRecentParties(string userName, int pageIndex, int pageSize)
        {
            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException(userName);
            }
            return this.partyRepository.FindMyRecentParties(userName, pageIndex, pageSize);
        }


        public IEnumerable<PartyDTO> MyInterest(int[] typeArray, string accountName, int pageIndex, int pageSize)
        {
            if (typeArray == null || typeArray.Count() <= 0)
            {
                throw new ArgumentNullException("Type array");
            }
            if (string.IsNullOrEmpty(accountName))
            {
                throw new ArgumentNullException("Account Name");
            }
            return this.partyRepository.FindMyInteret(typeArray, accountName, pageIndex, pageSize);
        }




        #region Remark Service
        public Remark GetRemark(int remarkID)
        {
            if (remarkID < 0)
            {
                throw new ArgumentOutOfRangeException("Id cannot be negative!");
            }
            return this.remarkRepository.FindBy(remarkID);
        }

        public IEnumerable<Remark> GerRemarkByParty(int partyID, int pageIndex, int pageSize)
        {
            if (partyID < 0 || pageIndex < 0 || pageSize < 0)
            {
                throw new ArgumentOutOfRangeException("Id or index cannot be negative!");
            }
            return this.remarkRepository.FindAll(r => r.PartyID == partyID, pageIndex, pageSize);
        }

        public IEnumerable<RemarkDTO> GetRemarkDTO(int partyID, int pageIndex, int pageSize)
        {
            return this.remarkRepository.FindRemarkDTO(partyID, pageIndex, pageSize);
        }

        public void AddRemark(Remark remark)
        {
            if (remark == null)
            {
                throw new ArgumentNullException("Item cannot be null!");
            }

            this.remarkRepository.Add(remark);
        }

        public void RemoveRemark(Remark remark)
        {
            if (remark == null)
            {
                throw new ArgumentNullException("Item cannot be null!");
            }

            this.remarkRepository.Remove(remark);
        }
        #endregion


        #region Party Rules validation
        private bool CanParticipateIn(UserPartyAssociation ups,DateTime partyDate,DateTime endDate)
        {
            bool result = true;
            if (ups == null)
            {
                throw new ArgumentNullException("user id");
            }
            var participatedList = this.partyRepository.FindByDate(partyDate, ups.UserID);
            if (participatedList != null && participatedList.Count() > 0)
            {
                var filteredList = participatedList.Where(e => Math.Abs((e.PartyDate.Value - partyDate).Hours) <= 1 || Math.Abs((e.EndDate - endDate).Hours) <= 1);
                if (filteredList != null && filteredList.Count() > 0)
                {
                    result = false;
                }
                //var beforeAttendList = participatedList.Where(e => e.PartyDate.Value > endDate && (e.PartyDate.Value - endDate).Hours <= 1);
                //if (beforeAttendList != null && beforeAttendList.Count() > 0)
                //{
                //    result = false;
                //}
                //var afterAttendList = participatedList.Where(e => e.EndDate < partyDate && (partyDate - e.EndDate).Hours <= 1);
                //if (afterAttendList != null && afterAttendList.Count() > 0)
                //{
                //    result = false;
                //}
            }
            //var list = userPartyAssRepository.FindAll(p => p.UserID == ups.UserID && p.IsLead == 0);
            //foreach (var item in participatedList)
            //{


            //    var day = ups.AssociationDate.Date - item.AssociationDate.Date;
            //    var tmp = participatedList.Where(e => (partyDate - e.PartyDate.Value).Hours <= 1);
            //    if (tmp != null && tmp.Count() > 0)
            //    {
            //        result = false;
            //    }
            //}
            return result;

        }

        private bool CanPublish(UserPartyAssociation ups,DateTime publishDate,DateTime endDate)
        {
            bool result = true;
            if (ups == null)
            {
                throw new ArgumentNullException("user id");
            }
            var engagedList = this.partyRepository.FindByDate(publishDate, ups.UserID);
            if (engagedList != null && engagedList.Count() > 0)
            {
                var filteredList = engagedList.Where(e=>Math.Abs((e.PartyDate.Value- publishDate).Hours) <= 1  || Math.Abs((e.EndDate - endDate).Hours) <= 1);
                if (filteredList != null && filteredList.Count() > 0)
                {
                    result = false;
                }
                //var beforeAttendList = engagedList.Where(e => e.PartyDate.Value > endDate && (e.PartyDate.Value-endDate).Hours <=1);
                //if (beforeAttendList != null && beforeAttendList.Count() > 0)
                //{
                //    result = false;
                //}
                //var afterAttendList = engagedList.Where(e=>e.EndDate < publishDate && (publishDate - e.EndDate).Hours <= 1);
                //if(afterAttendList != null && afterAttendList.Count() > 0 )
                //{
                //    result = false;
                //}
                
                //var tmp = engagedList.Where(e => (publishDate - e.PartyDate.Value).Hours <= 1);
                //if (tmp != null && tmp.Count() > 0)
                //{
                //    result = false;
                //}
            }
            return result;
        }
        #endregion


        #region Invitation Service

        public void Invite(Invitation invatation)
        {
            if (invatation == null)
            {
                throw new ArgumentNullException("Invitation");
            }
            invatation.SenderID = this.userRepository.FindByName(invatation.SenderAccount).UserID;
            var user = this.userPartyAssRepository.FindAll(u => u.UserID == invatation.UserID && u.PartyID == invatation.PartyID);
            if (user != null && user.Count() > 0)
            {
                throw new PartyEngagedException("已经参加了该活动");
            }
            var list = this.invitationRepository.FindAll(i => i.UserID == invatation.UserID && i.PartyID == invatation.PartyID);
            if (list != null && list.Count() > 0)
            {
                throw new InvitationExistException("该会员已经被邀请过参加该活动了");
            }

            this.invitationRepository.Add(invatation);
        }

        public void Invite(List<Invitation> list)
        {
            if (list == null)
            {
                throw new ArgumentNullException("list");
            }
            int senderID = this.userRepository.FindByName(list.FirstOrDefault().SenderAccount).UserID;
            foreach (var item in list)
            {
                item.SenderID = senderID;
                this.invitationRepository.Add(item);
            }
        }

        public void ConfirmInvitation(int invitationID)
        {
            if (invitationID < 0)
            {
                throw new ArgumentOutOfRangeException("invitation id");
            }
            var invitation = this.invitationRepository.FindBy(invitationID);
            invitation.IsConfirmed = true;
     
            UserPartyAssociation upa = new UserPartyAssociation
            {
                IsLead = 0,
                PartyID = invitation.PartyID,
                UserID = invitation.UserID,
                AssociationDate = DateTime.Now
            };
          
            //
            var bonus = this.bonusRepository.FindByUser(upa.UserID);
            if (bonus.Bonuses.HasValue)
            {
                if (bonus.Bonuses.Value < 15)
                {
                    throw new BounsNotEnoughException("您的积分目前不够，请充值!");
                }
            }
            this.invitationRepository.Save(invitation);
            this.userPartyAssRepository.Add(upa);

            // Calculate bonus
            if (bonus != null)
            {
                BonusCalculateStep tmpStep = new BonusCalculateStep();
                tmpStep.OriginalBonus = bonus.Bonuses.Value;
                tmpStep.UserID = upa.UserID;
                tmpStep.PartyID = upa.PartyID;
                tmpStep.IsSuccess = false;
                tmpStep.PartyStatus = (int)PartyStatus.Open;
                tmpStep.CreateDate = DateTime.Now;
                tmpStep.Step = "TemporaryDistrain";
                tmpStep.Deduct = BonusRuleFactory.GetBonusRuleService().TemporaryDistrain;
                this.bonusCalculateRepository.Add(tmpStep);

                bonus.Bonuses = tmpStep.OriginalBonus + tmpStep.Deduct;
                bonus.UpdateDate = DateTime.Now;
                this.bonusRepository.Save(bonus);


                // Add bonus log
                BonusLog log = new BonusLog
                {
                    Bonus = tmpStep.Deduct,
                    CreateDate = DateTime.Now,
                    PartyID = upa.PartyID,
                    UserID = upa.UserID,
                    Desc = "参加（好友邀请）活动暂扣积分"
                };
                this.bonusLogRepository.Add(log);
            }

        }


        public IEnumerable<Invitation> GetInvitation(string accountName, int pageIndex, int pageSize)
        {

            if (string.IsNullOrEmpty(accountName))
            {
                throw new ArgumentNullException("Account name");
            }
            var currentUser = this.userRepository.FindByName(accountName);
            if (currentUser == null)
            {
                throw new ArgumentNullException("User");
            }
            return this.invitationRepository.FindAll(i => i.IsConfirmed == false && i.UserID == currentUser.UserID, pageIndex, pageSize);

        }


        public IEnumerable<Domain.DTO.InvitationDTO> GetInvitationDTO(string accountName, int pageIndex, int pageSize)
        {
            if (string.IsNullOrEmpty(accountName))
            {
                throw new ArgumentNullException("Account name cannot be null!");
            }
            return this.invitationRepository.FindInvitationDTO(accountName, pageIndex, pageSize);
        }
        #endregion




        #region Bonus
        public IEnumerable<BonusLog> GetBonusLog(string accountName, int pageIndex, int pageSize)
        {
            if (string.IsNullOrEmpty(accountName))
            {
                throw new ArgumentOutOfRangeException("User id");
            }
            var user = this.userRepository.FindByName(accountName);

            if (user != null)
            {
                return this.bonusLogRepository.FindAll(b => b.UserID == user.UserID, pageIndex, pageSize);
            }
            return null;


        }

        public void AddBonusLog(BonusLog log)
        {
            if (log == null)
            {
                throw new ArgumentNullException("Bonus Log");
            }
            log.CreateDate = DateTime.Now;
            this.bonusLogRepository.Add(log);
        }

        public void DeleteBonusLog(BonusLog log)
        {
            if (log == null)
            {
                throw new ArgumentNullException("Bonus Log");
            }
            this.bonusLogRepository.Remove(log);
        }

        public void AddBonus(Bonus bonuse)
        {
            if (bonuse == null)
            {
                throw new ArgumentNullException("Bonus");
            }
            bonuse.CreateDate = DateTime.Now;
            this.bonusRepository.Add(bonuse);
        }

        public void UpdateBonus(Bonus bonus)
        {
            if (bonus == null)
            {
                throw new ArgumentNullException("Bonus");
            }
            bonus.UpdateDate = DateTime.Now;
            this.bonusRepository.Save(bonus);
        }

        public void AddBonus(IEnumerable<Bonus> list)
        {
            foreach (var item in list)
            {
                this.bonusRepository.Add(item);
            }
        }

        public void UpdateBonus(IEnumerable<Bonus> list)
        {
            foreach (var item in list)
            {
                this.bonusRepository.Save(item);
            }
        }

        public Bonus GetBonus(string accountName)
        {
            if (string.IsNullOrEmpty(accountName))
            {
                throw new ArgumentNullException("Account name");
            }
            var user = this.userRepository.FindByName(accountName);
            if (user != null)
            {
                return this.bonusRepository.FindByUser(user.UserID);
            }
            return null;
        }
        #endregion



        public IEnumerable<InvitationHistoryDTO> GetInvitationHistoryDTO(string accountName, int pageIndex, int pageSize)
        {
            if (string.IsNullOrEmpty(accountName))
            {
                throw new ArgumentNullException("Account name");
            }
            return this.invitationRepository.FindInvitationHistoryDTO(accountName, pageIndex, pageSize);
        }


        #region Party Service
        public void AddPartyType(string name, int type)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("Type name");
            }
            DLM.Domain.Model.Type partyType = new Domain.Model.Type
            {
                Name = name,
                PartyType = type,

            };
            this.partyTypeRepository.Add(partyType);

        }

        public void UpdatePartyType(int pid, string name)
        {
            if (pid < 0)
            {
                throw new ArgumentOutOfRangeException("Type id");
            }
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("Name");
            }
            var type = this.partyTypeRepository.FindBy(pid);
            type.Name = name;
            this.partyTypeRepository.Save(type);
        }

        public void RemovePartyType(int pid)
        {
            if (pid < 0)
            {
                throw new ArgumentOutOfRangeException("Type id");
            }
            var type = this.partyTypeRepository.FindBy(pid);
            this.partyTypeRepository.Remove(type);
        }

        public IEnumerable<Domain.Model.Type> GetPartyType()
        {
            return this.partyTypeRepository.FindAll();
        }
        #endregion

        #region Modality Service
        public void AddModality(Modality modality)
        {
            if (modality == null)
            {
                throw new ArgumentNullException("Modality");
            }
            this.modalityRepository.Add(modality);
        }

        public void UpdateModality(Modality modality)
        {
            if (modality == null)
            {
                throw new ArgumentNullException("Modality");
            }
            this.modalityRepository.Save(modality);
        }

        public void RemoveModality(int mid)
        {
            if (mid < 0)
            {
                throw new ArgumentNullException("Modality");
            }
            var modality = this.modalityRepository.FindBy(mid);
            this.modalityRepository.Remove(modality);
        }

        public Modality GetModality(int mid)
        {
            if (mid < 0)
            {
                throw new ArgumentNullException("Mid");
            }
            return this.modalityRepository.FindBy(mid);
        }

        public IEnumerable<Modality> GetModalityByType(int pid)
        {
            if (pid < 0)
            {
                throw new ArgumentNullException("pid");
            }
            return this.modalityRepository.FindAll(m => m.PID == pid);
        }
        #endregion

        #region Supplier Service
        public void AddSupplier(Supplier supplier)
        {
            if (supplier == null)
            {
                throw new ArgumentNullException("Supplier");
            }
            this.supplierRepository.Add(supplier);
        }

        public void UpdateSupplier(Supplier supplier)
        {
            if (supplier == null)
            {
                throw new ArgumentNullException("Supplier");
            }
            this.supplierRepository.Save(supplier);
        }

        public void RemoveSupplier(int sid)
        {
            if (sid < 0)
            {
                throw new NotImplementedException("Supplier");
            }
            var supplier = this.supplierRepository.FindBy(sid);
            this.supplierRepository.Remove(supplier);
        }

        public IEnumerable<Supplier> GetSupplier(int pageIndex, int pageSize)
        {
            return this.supplierRepository.FindAll(pageIndex, pageSize);
        }

        public IEnumerable<Supplier> GetSupplier(int mid)
        {
            if (mid < 0)
            {
                throw new ArgumentNullException("Mid");
            }
            return this.supplierRepository.FindAll(s => s.MID == mid);
        }

        public IEnumerable<Supplier> GetSupplier(int mid, int pageIndex, int pageSize)
        {
            if (mid < 0)
            {
                throw new ArgumentNullException("Mid");
            }
            return this.supplierRepository.FindAll(s => s.MID == mid, pageIndex, pageSize);
        }
        #endregion

        public decimal SuccessRate(string accountName)
        {
            if (string.IsNullOrEmpty(accountName))
            {
                throw new ArgumentNullException("Account name");
            }
            return this.partyRepository.SuccessRate(accountName);
        }



        public IEnumerable<ModalityDTO> GetModalityDTOByType(int partyID, int pageIndex, int pageSize)
        {
            if (partyID < 0)
            {
                throw new ArgumentOutOfRangeException("Party id");
            }
            return this.modalityRepository.FindModalityDTO(partyID, pageIndex, pageSize);
        }

        public IEnumerable<ModalityDTO> GetModalityDTO(int pageIndex, int pageSize)
        {
            return this.modalityRepository.FindModalityDTO(pageIndex, pageSize);
        }

        public IEnumerable<PartyDTO> SearchParty(int pageIndex, int pageSize, string type, string location, string partyType, string partyDate)
        {
            IEnumerable<PartyDTO> result = null;
            IEnumerable<string> tmpLocation;
            string newLocation = string.Empty;
            DateTime date = DateTime.Now;
            if (!string.IsNullOrEmpty(location))
            {
                // tmpLocation = location.Split('-').Where(s => !string.IsNullOrEmpty(s));

                newLocation = location.Replace('-', ',').Replace(',', ' ').Trim();

                if (string.IsNullOrEmpty(newLocation))
                {
                    newLocation = string.Empty;
                }
                //foreach (var item in tmpLocation)
                //{
                //    newLocation += item + ",";
                //}
            }
            if (!string.IsNullOrEmpty(partyDate))
            {
                switch (partyDate)
                {
                    case "1":
                        date = DateTime.Now.AddMonths(-1);
                        break;
                    case "3":
                        date = DateTime.Now.AddMonths(-3);
                        break;
                    default:
                        break;
                }
            }

            switch (type)
            {
                case "Province":
                    result = this.partyRepository.FindByLocation(newLocation, pageIndex, pageSize);
                    break;
                case "Date":
                    result = this.partyRepository.FindByPartyDate(date, pageIndex, pageSize);
                    break;
                case "Category":
                    result = this.partyRepository.FindByCategory(int.Parse(partyType), pageIndex, pageSize);
                    break;
                case "All":
                    result = this.partyRepository.FindAll(newLocation, date, int.Parse(partyType), pageIndex, pageSize);
                    break;
                case "Or":
                    var tmpPlace = newLocation;
                    var tmpType = partyType;
                    var tmpDate = partyDate;
                    if (!string.IsNullOrEmpty(tmpPlace) && !string.IsNullOrEmpty(tmpType))
                    {
                        result = this.partyRepository.FindByLocationAndType(newLocation, int.Parse(partyType), pageIndex, pageSize);
                    }
                    else if (!string.IsNullOrEmpty(tmpPlace) && !string.IsNullOrEmpty(tmpDate))
                    {
                        result = this.partyRepository.FindByLocationAndDate(newLocation, date, pageIndex, pageSize);
                    }
                    else if (!string.IsNullOrEmpty(tmpType) && !string.IsNullOrEmpty(tmpDate))
                    {
                        result = this.partyRepository.FindByTypeAndDate(int.Parse(partyType), date, pageIndex, pageSize);
                    }
                    //result = this.partyRepository.FindByOr(newLocation, date, int.Parse(partyType), pageIndex, pageSize);
                    break;
                default:

                    break;
            }
            return result;
        }

        public void SendEmailInvitation(EmailInvitation invitation)
        {
            if (invitation == null)
            {
                throw new ArgumentNullException("Emain invitation");
            }
            var party = this.partyRepository.FindBy(invitation.PartyID);
            if (party != null)
            {
                invitation.SendDate = DateTime.Now;
                invitation.PartySubject = party.Subject;
                MailService mailService = new MailService(this.emailService);
                mailService.SendInvitationNotice(invitation);
                invitation.IsSent = true;
                this.emailInvitationRepository.Add(invitation);
            }
        }


        #region Party Album Service
        public IEnumerable<PartyAlbum> GetPartyAlbum(int partyID, int pageIndex, int pageSize)
        {
            return this.partyAlbumRepository.FindByParty(partyID, pageIndex, pageSize);
        }

        public PartyAlbum GetPartyAlbum(int paid)
        {
            return this.partyAlbumRepository.FindBy(paid);
        }

        public void AddAlbum(PartyAlbum album)
        {
            if (album == null)
            {
                throw new ArgumentNullException("Album");
            }
            var tmp = this.partyAlbumRepository.Where(a => a.PartyID == album.PartyID).Count();
            if (tmp != null && tmp >= 8)
            {
                throw new PhotoEnoughException("Party album");
            }
            album.CreateDate = DateTime.Now;
            this.partyAlbumRepository.Add(album);
        }

        public void DeleteAlbum(int paid)
        {
            var album = this.partyAlbumRepository.FindBy(paid);
            this.partyAlbumRepository.Remove(album);
        }
        #endregion




        public void BatchQuit(int partyID)
        {
            var list = this.userPartyAssRepository.FindAll(p => p.PartyID == partyID);
            foreach (var item in list)
            {
                this.userPartyAssRepository.Remove(item);
            }
        }
    }
}
